/* Copyright (c) 2004-2024 Peigen.info. All rights reserved. */

package info.peigen.hotpot.business.fee.core.service.processor.calculate;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import com.alibaba.fastjson2.JSON;
import info.peigen.hotpot.business.fee.core.domain.Fee;
import info.peigen.hotpot.business.fee.core.domain.FeeContext;
import info.peigen.hotpot.business.fee.core.domain.FeeLog;
import info.peigen.hotpot.business.fee.core.domain.FeeRule;
import info.peigen.hotpot.business.fee.core.service.processor.base.AbstractFeeServiceProcessor;
import info.peigen.hotpot.business.fee.facade.command.order.FeeOrder;
import info.peigen.hotpot.common.core.lang.money.Money;
import info.peigen.hotpot.common.core.result.ResultCode;
import info.peigen.hotpot.common.service.base.exception.BusinessException;
import info.peigen.hotpot.common.service.base.processor.Processor;
import info.peigen.hotpot.common.service.base.processor.ProcessorServiceContext;
import info.peigen.hotpot.common.service.base.time.TimeRange;
import org.noear.solon.annotation.Component;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * <b>(CalculateFeeProcessor)</b>
 *
 * @author Peigen
 * @version 1.0.0
 * @since 2022/6/3
 */
@Component
public class CalculateFeeProcessor extends AbstractFeeServiceProcessor implements Processor {
    @Override
    public Integer level() {
        return 20;
    }

    @Override
    public void execute(ProcessorServiceContext serviceContext) {
        Fee fee = (Fee) serviceContext.getDomain();

        FeeOrder order = (FeeOrder) serviceContext.getOrder();
        FeeRule  rule  = fee.getRule();
        Money    feeAmount;
        switch (rule.getMethod()) {
            case Ratio:
                feeAmount = fee.getTransAmount().multiply(Double.parseDouble(rule.getContext()));
                fee.setFeeAmount(feeAmount);
                feeLog(fee.getFeeLog(), feeAmount, rule);
                break;
            case Fixed_Amount:
            default:
                fixedAmount(fee, rule.getContext(), order);
                break;
        }

        serviceContext.setDomain(fee);
    }

    private void fixedAmount(Fee fee, String context, FeeOrder order) {
        boolean isSpecifyAmount = ObjUtil.isNotNull(order.getTransAmount()) && !NumberUtil.equals(order.getTransAmount().getAmount(), new BigDecimal(0));
        if (isSpecifyAmount) {
            fee.setFeeAmount(order.getTransAmount());
            fee.setChargeFeeAmount(order.getTransAmount().multiply(0.8d));
            fee.setServiceFeeAmount(order.getTransAmount().multiply(0.2d));
        } else {
            String           feeContextString = context.replaceAll("24:00", "00:00");
            List<FeeContext> contexts         = JSON.parseArray(feeContextString, FeeContext.class);
            SimpleDateFormat df               = new SimpleDateFormat("HH:mm:ss");
            DateTime         now              = DateUtil.parse(df.format(new Date()));
            List<FeeContext> contextResults = contexts.stream().filter(each -> TimeRange.isIn(now, each.getTimeRange().getStartTime(), each.getTimeRange().getEndTime()))
                    .toList();

            Assert.isTrue(contextResults.size() == 1, () -> new BusinessException(ResultCode.FAILURE, "激活失败，费用规则无法计算[context]=" + context));
            FeeContext realRule         = contextResults.stream().findFirst().get();
            Money      chargeFeeAmount  = realRule.getChargeFee().multiply(order.getChargingCount());
            Money      serviceFeeAmount = realRule.getServiceFee().multiply(order.getChargingCount());
            fee.setFeeAmount(chargeFeeAmount.add(serviceFeeAmount))
                    .setChargeFeeAmount(chargeFeeAmount)
                    .setServiceFeeAmount(serviceFeeAmount);
        }
        feeLog(fee);
    }

    private void feeLog(Fee fee) {
        fee.getFeeLog().setFeeAmount(fee.getFeeAmount())
                .setChargeFeeAmount(fee.getChargeFeeAmount())
                .setServiceFeeAmount(fee.getServiceFeeAmount())
                .setPayeeAccount(fee.getRule().getPayeeAccount())
                .setAccount(fee.getRule().getPayerAccount());
    }

    private void feeLog(FeeLog feeLog, Money feeAmount, FeeRule rule) {
        feeLog.setFeeAmount(feeAmount);
        feeLog.setPayeeAccount(rule.getPayeeAccount());
        feeLog.setAccount(rule.getPayerAccount());
    }

}